﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;
using kangsuce.Admin.MessageHandler;
using kangsuce.BLL;
using kangsuce.Model;
using kangsuce.Common;
using Newtonsoft.Json;
using Senparc.Weixin;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs;
using Senparc.Weixin.MP.AdvancedAPIs.OAuth;
using Senparc.Weixin.MP.Containers;
using Senparc.Weixin.MP.Entities.Request;
using Senparc.Weixin.MP.Helpers;

namespace kangsuce.Admin.Controllers
{
    public class WeiXinController : Controller
    {
        private readonly WxUserBLL wxUserBll = new WxUserBLL();
        private readonly DetectionResultBLL detectionResultBLL = new DetectionResultBLL();
        private readonly VideoBLL videoBLL = new VideoBLL();

        private string doMain = ConfigurationManager.AppSettings["doMain"]; //项目域名
        private KSC_WxConfig wxConfig => Common.Common.GetWxConfigText(Server.MapPath("/config/weixin.xml"));

        private readonly Func<string> _getRandomFileName =
            () => DateTime.Now.ToString("yyyyMMdd-HHmmss") + Guid.NewGuid().ToString("n").Substring(0, 6);

        public string access_token => GetAccessToken();

        public OAuthUserInfo wxUserInfo => GetUserInfo();

        /// <summary>
        /// 获取accessToken
        /// </summary>
        /// <returns></returns>
        private string GetAccessToken()
        {
            return AccessTokenContainer.TryGetAccessToken(wxConfig.AppId, wxConfig.AppSecret, false);
        }

        /// <summary>
        /// 获取微信用户信息
        /// </summary>
        /// <returns></returns>
        private OAuthUserInfo GetUserInfo()
        {
            OAuthUserInfo model = null;
            if (Session["userInfo"] != null)
            {
                model = Session["userInfo"] as OAuthUserInfo;
            }
            return model;
        }

        /// <summary>
        /// 控制器验证
        /// </summary>
        /// <param name="filterContext"></param>
        protected override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
        {
            string[] excludeUrl = new[] {"/weixin/userinfocallback", "/weixin/wxhome", "/weixin/getcode", "/weixin/detectionresultscan" };
            if (!excludeUrl.Contains(filterContext.HttpContext.Request.Path.ToLower()))
            {
                if (wxUserInfo == null)
                {
                    if (filterContext.HttpContext.Request.IsAjaxRequest())
                    {
                        filterContext.Result = Json(new {result = "error", msg = "用户信息丢失，请重新登录"},
                            JsonRequestBehavior.AllowGet);
                    }
                    else
                    {
                        filterContext.Result = RedirectToAction("GetCode", "WeiXin",
                            new {returnUrl = filterContext.HttpContext.Request.RawUrl});
                    }
                }
                base.OnAuthorization(filterContext);
            }
        }

        #region 微信验证

        /// <summary>
        /// 微信配置验证地址
        /// </summary>
        /// <param name="signature"></param>
        /// <param name="timestamp"></param>
        /// <param name="nonce"></param>
        /// <param name="echostr"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("WxHome")]
        public ActionResult Get(string signature, string timestamp, string nonce, string echostr)
        {
            if (CheckSignature.Check(signature, timestamp, nonce, wxConfig.Token))
            {
                return Content(echostr); //返回随机字符串则表示验证通过
            }
            else
            {
                return
                    Content("failed:" + signature + "," + CheckSignature.GetSignature(timestamp, nonce, wxConfig.Token) +
                            "。如果您在浏览器中看到这条信息，表明此Url可以填入微信后台。");
            }
        }

        /// <summary>
        /// 用户发送消息后，微信平台自动Post一个请求到这里，并等待响应XML。
        /// PS：此方法为简化方法，效果与OldPost一致。
        /// v0.8之后的版本可以结合Senparc.Weixin.MP.MvcExtension扩展包，使用WeixinResult，见MiniPost方法。
        /// </summary>
        [HttpPost]
        [ActionName("WxHome")]
        public ActionResult Post(PostModel postModel)
        {
            if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, wxConfig.Token))
            {
                return Content("参数错误！");
            }

            postModel.Token = wxConfig.Token; //根据自己后台的设置保持一致
            postModel.EncodingAESKey = wxConfig.EncodingAESKey; //根据自己后台的设置保持一致
            postModel.AppId = wxConfig.AppId; //根据自己后台的设置保持一致

            var logPath = Server.MapPath($"~/App_Data/MP/{DateTime.Now.ToString("yyyy-MM-dd")}/");
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }

            //自定义MessageHandler，对微信请求的详细判断操作都在这里面。
            var messageHandler = new CustomMessageHandler(Request.InputStream);


            try
            {
                //测试时可开启此记录，帮助跟踪数据，使用前请确保App_Data文件夹存在，且有读写权限。
                messageHandler.RequestDocument.Save(Path.Combine(logPath,
                    $"{_getRandomFileName()}_Request_{messageHandler.RequestMessage.FromUserName}.txt"));
                if (messageHandler.UsingEcryptMessage)
                {
                    messageHandler.EcryptRequestDocument.Save(Path.Combine(logPath,
                        $"{_getRandomFileName()}_Request_Ecrypt_{messageHandler.RequestMessage.FromUserName}.txt"));
                }

                /* 如果需要添加消息去重功能，只需打开OmitRepeatedMessage功能，SDK会自动处理。
                 * 收到重复消息通常是因为微信服务器没有及时收到响应，会持续发送2-5条不等的相同内容的RequestMessage*/
                messageHandler.OmitRepeatedMessage = true;


                //执行微信处理过程
                messageHandler.Execute();

                //测试时可开启，帮助跟踪数据

                //if (messageHandler.ResponseDocument == null)
                //{
                //    throw new Exception(messageHandler.RequestDocument.ToString());
                //}

                messageHandler.ResponseDocument?.Save(Path.Combine(logPath,
                    $"{_getRandomFileName()}_Response_{messageHandler.RequestMessage.FromUserName}.txt"));

                if (messageHandler.UsingEcryptMessage)
                {
                    //记录加密后的响应信息
                    messageHandler.FinalResponseDocument.Save(Path.Combine(logPath,
                        $"{_getRandomFileName()}_Response_Final_{messageHandler.RequestMessage.FromUserName}.txt"));
                }

                return Content(messageHandler.ResponseDocument.ToString()); //v0.7-
                //return new FixWeixinBugWeixinResult(messageHandler);//为了解决官方微信5.0软件换行bug暂时添加的方法，平时用下面一个方法即可
                //return new WeixinResult(messageHandler);//v0.8+
            }
            catch (Exception ex)
            {
                using (
                    TextWriter tw = new StreamWriter(Server.MapPath("~/App_Data/Error_" + _getRandomFileName() + ".txt"))
                    )
                {
                    tw.WriteLine("ExecptionMessage:" + ex.Message);
                    tw.WriteLine(ex.Source);
                    tw.WriteLine(ex.StackTrace);
                    //tw.WriteLine("InnerExecptionMessage:" + ex.InnerException.Message);

                    if (messageHandler.ResponseDocument != null)
                    {
                        tw.WriteLine(messageHandler.ResponseDocument.ToString());
                    }

                    if (ex.InnerException != null)
                    {
                        tw.WriteLine("========= InnerException =========");
                        tw.WriteLine(ex.InnerException.Message);
                        tw.WriteLine(ex.InnerException.Source);
                        tw.WriteLine(ex.InnerException.StackTrace);
                    }

                    tw.Flush();
                    tw.Close();
                }
                return Content("");
            }
        }

        /// <summary>
        /// 方式回调
        /// </summary>
        /// <param name="code"></param>
        /// <param name="returnUrl">用户最初尝试进入的页面</param>
        /// <returns></returns>
        public ActionResult UserInfoCallback(string code, string returnUrl)
        {
            if (string.IsNullOrEmpty(code))
            {
                return Content("您拒绝了授权！");
            }
            OAuthAccessTokenResult result = null;

            //通过，用code换取access_token
            try
            {
                result = OAuthApi.GetAccessToken(wxConfig.AppId, wxConfig.AppSecret, code);
            }
            catch (Exception ex)
            {
                return Content(ex.Message);
            }
            if (result.errcode != ReturnCode.请求成功)
            {
                return Content("错误：" + result.errmsg);
            }

            //因为第一步选择的是OAuthScope.snsapi_userinfo，这里可以进一步获取用户详细信息
            try
            {
                var _userInfo = OAuthApi.GetUserInfo(result.access_token, result.openid);
                Session["userInfo"] = _userInfo;
                if (!string.IsNullOrEmpty(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return Content("缺少参数：returnUrl");
            }
            catch (ErrorJsonResultException ex)
            {
                return Content(ex.Message);
            }
        }

        public ActionResult GetCode(string returnUrl)
        {
            string authorize = OAuthApi.GetAuthorizeUrl(wxConfig.AppId,
                doMain + "/Weixin/UserInfoCallback?returnUrl=" + returnUrl,
                "STATE#wechat_redirect", OAuthScope.snsapi_userinfo);
            return Redirect(authorize);
        }

        #endregion

        /// <summary>
        /// 首页
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            KSC_WxUser model = wxUserBll.GetModel(p => p.openId == wxUserInfo.openid);
            if (model == null)
            {
                LOG.LogDB.DebugTest1("UserEdit");
                return Redirect("UserEdit");
            }
            LOG.LogDB.DebugTest1(model.ConvertEntityToXmlString());
            LOG.LogDB.DebugTest1("Index");
            return View();
        }

        #region 个人中心

        /// <summary>
        /// 个人中心
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult UserInfo(int id = 0)
        {
            KSC_WxUser model = wxUserBll.GetModelById(id) ?? new KSC_WxUser {userId = 0};
            ViewBag.Json = JsonConvert.SerializeObject(model);
            return View();
        }

        /// <summary>
        /// 个人资料编辑
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult UserEdit(int id = 0)
        {
            KSC_WxUser model = wxUserBll.GetModelById(id) ?? new KSC_WxUser {userId = 0};
            ViewBag.Json = JsonConvert.SerializeObject(model);
            return View(wxUserInfo);
        }

        /// <summary>
        /// 微信用户信息保存
        /// </summary>
        /// <returns></returns>
        public ActionResult UserSave(KSC_WxUser model)
        {
            try
            {
                int userId = Request.Form["userId"].ToInt32();
                if (userId == 0) //新增
                {
                    KSC_WxUser addModel = new KSC_WxUser
                    {
                        birthDate = model.birthDate, //出生日期
                        createDate = DateTime.Now,
                        dietIsRules = model.dietIsRules, // 饮食是否规律 0：否 1：是 
                        diabetesHistory = model.diabetesHistory, // 直系亲属糖尿病史 0：无1：父母 2：祖辈 3：不知道 
                        drinkStatus = model.drinkStatus, //饮酒状况 0：从不 1：偶尔 2：经常 3：每天 
                        height = model.height, //身高
                        hypertensionHistory = model.hypertensionHistory, // 直系亲属高血压史 0：无1：父母 2：祖辈 3：不知道 
                        motionStatus = model.motionStatus, // 运动状况 0：从不 1：偶尔 2：经常 3：每天 
                        headImgUrl = wxUserInfo.headimgurl, //微信头像
                        nickName = wxUserInfo.nickname, //微信昵称
                        openId = wxUserInfo.openid,
                        phone = model.phone, //手机号
                        sleepIsRules = model.sleepIsRules, // 睡眠是否规律 0：否 1：是
                        smokeStatus = model.smokeStatus, // 吸烟状况 0：否 1：是 2：已戒烟 
                        specialPeriod = model.specialPeriod, // 特殊时期 0：无 1：备孕 2：怀孕 3：哺乳期 
                        tumorPatients = model.tumorPatients, // 直系亲属肿瘤患者 0：无1：父母 2：祖辈 3：不知道 
                        weight = model.weight, //体重
                        userSex = model.userSex, //性别
                        isDelete = false
                    };
                    userId = wxUserBll.Insert(addModel);
                    return Json(new {result = userId > 0 ? "success" : "error", msg = userId > 0 ? "新增成功" : "新增失败"});
                }
                else //编辑
                {
                    KSC_WxUser editModel = wxUserBll.GetModelById(userId);
                    editModel.birthDate = model.birthDate;
                    editModel.dietIsRules = model.dietIsRules; // 饮食是否规律 0：否 1：是 
                    editModel.diabetesHistory = model.diabetesHistory; // 直系亲属糖尿病史 0：无1：父母 2：祖辈 3：不知道 
                    editModel.drinkStatus = model.drinkStatus; //饮酒状况 0：从不 1：偶尔 2：经常 3：每天 
                    editModel.height = model.height; //身高
                    editModel.hypertensionHistory = model.hypertensionHistory; // 直系亲属高血压史 0：无1：父母 2：祖辈 3：不知道 
                    editModel.motionStatus = model.motionStatus; // 运动状况 0：从不 1：偶尔 2：经常 3：每天 
                    editModel.headImgUrl = wxUserInfo.headimgurl; //微信头像
                    editModel.nickName = wxUserInfo.nickname; //微信昵称
                    editModel.openId = wxUserInfo.openid;
                    editModel.phone = model.phone; //手机号
                    editModel.sleepIsRules = model.sleepIsRules; // 睡眠是否规律 0：否 1：是
                    editModel.smokeStatus = model.smokeStatus; // 吸烟状况 0：否 1：是 2：已戒烟 
                    editModel.specialPeriod = model.specialPeriod; // 特殊时期 0：无 1：备孕 2：怀孕 3：哺乳期 
                    editModel.tumorPatients = model.tumorPatients; // 直系亲属肿瘤患者 0：无1：父母 2：祖辈 3：不知道 
                    editModel.weight = model.weight; //体重
                    editModel.userSex = model.userSex; //性别
                    bool result = wxUserBll.Update(editModel);
                    return Json(new {result = result ? "success" : "error", msg = result ? "修改成功" : "修改失败"});
                }
            }
            catch (Exception ex)
            {
                return Json(new {result = "error", msg = ex.Message});
            }
        }

        #endregion

        /// <summary>
        /// 检测方式
        /// </summary>
        /// <returns></returns>
        public ActionResult CheckMode()
        {
            var jssdkUiPackage = JSSDKHelper.GetJsSdkUiPackage(wxConfig.AppId, wxConfig.AppSecret,
                Request.Url.AbsoluteUri);

            return View(jssdkUiPackage);
        }

        #region 检测结果

        /// <summary>
        /// 检测结果添加
        /// </summary>
        /// <returns></returns>
        public ActionResult DetectionResultAdd()
        {
            return View();
        }

        /// <summary>
        /// 检测结果备注编辑
        /// </summary>
        /// <returns></returns>
        public ActionResult DetectionResultEdit()
        {
            return View();
        }

        /// <summary>
        /// 检测结果添加
        /// </summary>
        /// <returns></returns>
        public ActionResult DetectionResultSave(KSC_DetectionResult model)
        {
            try
            {
                int detectionResultId = Request.Form["detectionResultId"].ToInt32();
                if (detectionResultId == 0)
                {
                    detectionResultId = detectionResultBLL.Insert(model);
                    return
                        Json(
                            new
                            {
                                result = detectionResultId > 0 ? "success" : "error",
                                msg = detectionResultId > 0 ? "新增成功" : "新增失败"
                            });
                }
                else
                {
                    KSC_DetectionResult editModel = detectionResultBLL.GetModelById(detectionResultId);
                    editModel.remarks = model.remarks;
                    bool result = detectionResultBLL.Update(editModel);
                    return Json(new {result = result ? "success" : "error", msg = result ? "修改成功" : "修改失败"});
                }
            }
            catch (Exception ex)
            {
                return Json(new {result = "error", msg = ex.Message});
            }
        }

        /// <summary>
        /// 检测结果扫码页面
        /// </summary>
        /// <returns></returns>
        public ActionResult DetectionResultScan(int detectionItemId, int timeIntervalOptionId, decimal resultValue)
        {
            try
            {
                int detectionResultId = 0;

                KSC_DetectionResult model = new KSC_DetectionResult
                {
                    detectionTime = DateTime.Now,
                    detectionItemId = detectionItemId,
                    timeIntervalOptionId = timeIntervalOptionId,
                    resultValue = resultValue
                };
                detectionResultId = detectionResultBLL.Insert(model);
                if (detectionResultId > 0)
                {
                    return RedirectToAction("DetectionResultList", "WeiXin", new { detectionItemId = detectionItemId });
                }
                else
                {
                    return Json(new {result = "error", msg = "新增失败"});
                }
            }
            catch (Exception ex)
            {
                return Json(new {result = "error", msg = ex.Message});
            }
        }

        /// <summary>
        /// 检测结果列表
        /// </summary>
        /// <returns></returns>
        public ActionResult DetectionResultList()
        {
            return View();
        }

        /// <summary>
        /// 获取检测结果列表数据
        /// </summary>
        /// <param name="pageSize">分页大小</param>
        /// <param name="pageNumber">页码</param>
        /// <returns></returns>
        public ActionResult GetDetectionResultList(int pageSize, int pageNumber)
        {
            try
            {
                int total;
                var list = videoBLL.GetListByPage(pageSize, pageNumber, out total,
                    orderBy: c => c.OrderBy(p => p.videoId));
                return Json(new {rows = list, total = total}, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new {result = "error", msg = ex.Message}, JsonRequestBehavior.AllowGet);
            }
        }

        #endregion

        #region 视频

        /// <summary>
        /// 视频列表
        /// </summary>
        /// <returns></returns>
        public ActionResult VideoList()
        {
            return View();
        }

        /// <summary>
        /// 获取视频列表数据
        /// </summary>
        /// <param name="pageSize">分页大小</param>
        /// <param name="pageNumber">页码</param>
        /// <param name="name"></param>
        /// <returns></returns>
        public ActionResult GetVideoList(int pageSize, int pageNumber, string name = "")
        {
            try
            {
                int total;
                var list = videoBLL.GetListByPage(pageSize, pageNumber, out total,
                    p => name == "" || p.videoName.Contains(name),
                    c => c.OrderBy(p => p.videoId));
                return Json(new {rows = list, total = total}, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new {result = "error", msg = ex.Message}, JsonRequestBehavior.AllowGet);
            }
        }

        #endregion
    }
}